회고

[우아한테크코스 프리코스] 문자열 계산기 과제 회고

문자열 계산기 과제는 요구 사항 분리, 객체 지향 설계, 예외 상황 처리를 학습하는 기회였다. 이 과정에서 겪은 설계 변경, 디버깅, 환경 설정 문제를 정리했다.

1. 설계와 리팩토링: 컨트롤러 도입과 예외 처리

컨트롤러 도입을 통한 관심사 분리

초기 설계는 Application 클래스가 객체 생성과 실행 흐름을 모두 담당했다. '관심사의 분리' 원칙을 적용하기 위해, 로직 실행을 담당하는 CalculatorController를 추가로 도입했다.

트러블슈팅: assertThatThrownBy 테스트 실패

컨트롤러 run() 메서드에 try-catch 문을 배치하자, IllegalArgumentException을 검증하는 assertThatThrownBy 테스트가 실패했다.

원인: 컨트롤러의 catch 블록이 예외를 처리한 후 전파하지 않아, 테스트 코드에서 예외를 감지하지 못했다.

// 문제가 발생했던 컨트롤러의 예외 처리
public void run() {
    try {
        // ... 로직 실행 ...
    } catch (IllegalArgumentException e) {
        // 여기서 예외를 잡고 종료
        OutputView.printError(e.getMessage());
    }
}

해결: 에러 메시지 출력 책임은 컨트롤러에 유지하기로 했다. catch 블록에서 에러 메시지를 출력한 뒤, throw e;를 사용해 예외를 다시 던지는(re-throw) 방식으로 해결했다.

// 수정한 컨트롤러의 예외 처리
public void run() {
    try {
        // ... 로직 실행 ...
    } catch (IllegalArgumentException e) {
        OutputView.printError(e.getMessage()); // 1. 에러 메시지 출력 처리
        throw e; // 2. 예외를 다시 던짐
    }
}

이 방식을 적용하자 테스트가 정상 통과했다. 이 과정에서 예외 처리 흐름과 테스트 코드의 상호작용을 명확히 이해할 수 있었다.

2. 기술적 난관과 디버깅

원인 1: 유효성 검사 및 파싱 순서 오류

음수 및 숫자 판별 로직에서 순서 문제를 발견했다.

문제 코드:

// ...
String[] textNumbers = text.split(delimiter);
int[] numbers = new int[textNumbers.length]; // 1. 배열 초기화 (모든 요소 0)

if(!isPositive(numbers)) { // 2. 파싱 전 유효성 검사
    throw new IllegalArgumentException("입력값에 양수가 아닌 숫자가 포함되어 있습니다.");
}

for(int i = 0; i < textNumbers.length; i++) { // 3. 실제 파싱
    numbers[i] = Integer.parseInt(textNumbers[i]);
}
// ...

원인: 문자열을 int로 파싱하기 전에 유효성 검사를 먼저 수행했다. new int[size]로 생성된 배열은 0으로 초기화되며, 유효성 검사 로직이 이 0을 유효하지 않은 값으로 판단하여 예외를 발생시켰다.

해결: 파싱을 먼저 수행하고, 파싱된 숫자 배열을 대상으로 유효성 검사를 하도록 순서를 변경했다.

원인 2: \n 처리 방식 오해

커스텀 구분자 요구사항("//;\n1;2;3")에서 \n의 처리를 고민했다. 테스트 코드를 분석한 결과, \n은 개행 문자가 아닌 구분자와 숫자 문자열을 나누는 단순 **'문자열 리터럴'**로 사용된 것을 확인했다. 따라서 split("\n")으로 문자열을 분리했다.

3. 환경 문제: WSL과 Java 버전 불일치

개발 환경 설정에서 예상치 못한 문제가 발생했다.

증상: IntelliJ에서는 WSL의 Java 21 버전으로 정상 동작했으나, 터미널에서 ./gradlew clean test 실행 시 테스트가 실패했다. 터미널의 java -version은 17로 확인되었다.

원인 추적: update-alternatives로 버전을 21로 변경해도 터미널 재시작 시 17로 복귀했다. 확인 결과 ~/.bashrc 파일에 JAVA_HOME이 17 버전으로 고정되어 있었다.

해결: ~/.bashrcJAVA_HOME 경로를 Java 21로 수정한 뒤 설정을 적용(source ~/.bashrc)했다. 이후 터미널 버전이 21로 일치되었다.

# ~/.bashrc
# export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 (문제의 원인)
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 # (수정)
export PATH=$JAVA_HOME/bin:$PATH

4. 최종 소감

예외 처리, 테스트 코드 동작 원리, 객체지향 설계, 개발 환경 일관성까지 고민해야 했다.

특히 WSL 환경에서 IDE와 터미널의 자바 버전 불일치 문제를 직접 경험하고 해결한 것이 의미 있었다. 코드 외적인 문제 해결의 중요성을 배울 수 있었다. 사실 설계하고 환경설정하는 것이 가장 어려운 것 같다.

추가 회고